package com.whiteape.book.presenter;

import com.whiteape.book.contract.ComicReadContract;
import com.whiteape.book.core.manager.MediaStorageManager;
import com.whiteape.book.core.manager.WebMediaManager;
import com.whiteape.book.model.bo.ChapterContentBo;
import com.whiteape.book.model.dto.CollectionMediaBean;
import com.whiteape.book.model.dto.MediaChapterBean;
import com.whiteape.book.model.dto.SiteSourceBean;
import com.whiteape.book.model.type.ComicLoadFlag;
import com.whiteape.book.ui.base.RxPresenter;
import com.whiteape.book.utils.GsonUtils;
import com.whiteape.book.utils.LogUtils;
import com.whiteape.book.utils.RxUtils;

import org.apache.commons.lang3.StringUtils;
import org.reactivestreams.Subscriber;
import org.reactivestreams.Subscription;

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import io.reactivex.Single;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;

public class ComicReadPresenter extends RxPresenter<ComicReadContract.View> implements ComicReadContract.Presenter {
    private List<String> mLoadedChapterIdList = new ArrayList<>();
    private Disposable disposable;


    @Override
    public void updateWebCatalog(SiteSourceBean siteSourceBean, CollectionMediaBean mediaBean) {

        loadCatalog(siteSourceBean, mediaBean, true);
    }

    @Override
    public void loadWebCatalog(SiteSourceBean siteSourceBean, CollectionMediaBean mediaBean) {
        loadCatalog(siteSourceBean, mediaBean, false);

    }

    private void loadCatalog(SiteSourceBean siteSourceBean, CollectionMediaBean mediaBean, boolean justUpdate) {
        LogUtils.d("loadWebCatalog");
        String bookChapterListUrl = mediaBean.getCatalogUrl();
        Disposable disposable = WebMediaManager.getInstance()
                .getCatalog(siteSourceBean, mediaBean)
//                .doOnSuccess(new Consumer<List<MediaChapterBean>>() {
//                    @Override
//                    public void accept(List<MediaChapterBean> bookChapterBean) throws Exception {
//                        //进行设定BookChapter所属的media的id。
//                        LogUtils.d("loadWebCatalog, accept, bookChapterBean is " + bookChapterBean);
//                        for (MediaChapterBean mediaChapterBean : bookChapterBean) {
//                            mediaChapterBean.setId(MD5Utils.strToMd5By16(mediaChapterBean.getLink()));
////                            mediaChapterBean.setLink(mediaChapterBean.getLink());
//                            mediaChapterBean.setMediaId(mediaBean.getId());
//                        }
//                    }
//                })
                .compose(RxUtils::toSimpleSingle)
                .subscribe(
                        beans -> {
                            LogUtils.d("loadWebCatalog, onSuccess, beans is " + beans);
                            if (beans == null || beans.isEmpty()) {
                                if (justUpdate) {

                                    mView.updateCatalogFailed();
                                } else {

                                    mView.loadCatalogFailed();
                                }
                            } else {
                                if (justUpdate) {

                                    mView.updateCatalog(beans);
                                } else {

                                    mView.showCatalog(beans);
                                }
                            }
                        }
                        ,
                        e -> {
                            //TODO: Haven't grate conversation method.
                            LogUtils.e(e);
                            e.printStackTrace();
                            mView.loadCatalogFailed();

                        }
                );
        addDisposable(disposable);

    }

    @Override
    public void lazyLoadImage(SiteSourceBean siteSourceBean, CollectionMediaBean collectionMediaBean, ChapterContentBo chapterContentBo) {
        addDisposable(WebMediaManager.getInstance().getComicContentLazy(siteSourceBean, collectionMediaBean, chapterContentBo)
                .compose(RxUtils::toSimpleSingle)
                .subscribe(chapterContentBoList -> {
                    if (chapterContentBoList != null && chapterContentBoList.size() > 0) {
                        mView.lazyLoadSuccess(chapterContentBoList.get(0));

                    }
                }, throwable -> mView.lazyLoadFailed(chapterContentBo)));
    }

    @Override
    public void saveChapterLazyContent(String mediaId, String chapterTitle, ChapterContentBo chapterContentBo) {
        String chapterId = chapterContentBo.getChapterId();
        if (StringUtils.isEmpty(chapterId)) {
            return;
        }

        Single.create(emitter -> {

            List<ChapterContentBo> boList = MediaStorageManager.getInstance().getComicChapterInfoBean(mediaId, chapterTitle);
            if (boList == null) {
                return;
            }
            for (ChapterContentBo bo : boList) {
                if (!chapterContentBo.getCurPartNum().equals(bo.getCurPartNum())) {
                    continue;
                }
                bo.setLazyLoading(false);
                bo.setContent(chapterContentBo.getContent());
                break;
            }

            String content = GsonUtils.obj2String(boList);
            addDisposable(MediaStorageManager.getInstance().saveChapterInfoInRx(
                    mediaId, chapterTitle, content
            ));
        }).compose(RxUtils::toSimpleSingle)
                .subscribe();
    }

    @Override
    public void loadChapter(SiteSourceBean siteSourceBean, CollectionMediaBean collectionMediaBean, List<MediaChapterBean> subMediaChapterBeanList, ComicLoadFlag flag) {

        String mediaId = collectionMediaBean.getId();
        Set<String> cachedChapterIdSet = new HashSet<>();
        //这里重新new一个list，是防止subList出来的数据，在原始数据变化的时候，产生ConcurrentModificationException
        List<MediaChapterBean> mediaChapterBeanList = new ArrayList<>(subMediaChapterBeanList);
        //如果是章节跳转的，就不需要判断id了，因为会先清空数据
        String chapterId = mediaChapterBeanList.get(0).getId();

        //如果不是章节跳转而是下一章/上一章，需要判断是否已经有在执行中的缓存请求了
        //因为可能会触发多次加载导致数据紊乱
        if (flag != ComicLoadFlag.LOAD_JUMP_CHAPTER &&
                mLoadedChapterIdList.contains(chapterId)) {
            return;
        }
        //先从本地缓存中查找有没有数据，有的章节，直接返回，没有的再获取网络章节内容
        for (MediaChapterBean bean : mediaChapterBeanList) {
            List<ChapterContentBo> contentBoList = MediaStorageManager.getInstance().getComicChapterInfoBean(mediaId, bean.getName());
            if (contentBoList != null && contentBoList.size() > 0) {
                mView.finishChapter(contentBoList, ComicLoadFlag.LOAD_NEXT, bean.getId());
                cachedChapterIdSet.add(bean.getId());
                mLoadedChapterIdList.add(bean.getId());

            }
        }

        //取消上次的任务，防止多次加载

//        if (mChapterSub != null) {
//            mChapterSub.cancel();
//        }
        int size = mediaChapterBeanList.size();
//        if(disposable != null) {
//            disposable.dispose();
//        }

        List<Single<List<ChapterContentBo>>> chapterInfoList = new ArrayList<>(size);
        ArrayDeque<String> titles = new ArrayDeque<>(size);

        // 将要下载章节，转换成网络请求。
        for (int i = 0; i < size; ++i) {
            MediaChapterBean mediaChapterBean = mediaChapterBeanList.get(i);
            if (cachedChapterIdSet.contains(mediaChapterBean.getId())) {
                continue;
            }
            mLoadedChapterIdList.add(mediaChapterBean.getId());
            // 网络中获取数据
            Single<List<ChapterContentBo>> chapterInfoSingle = WebMediaManager.getInstance()
                    .getComicChapterContent(siteSourceBean, collectionMediaBean, mediaChapterBean);

            chapterInfoList.add(chapterInfoSingle);

            titles.add(mediaChapterBean.getName());
        }

        //需要用retry，解决类似腾讯里面js概率因为document等不支持的浏览器参数导致的错误
        Single.concat(chapterInfoList)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .retry(3)
                .subscribe(new Subscriber<List<ChapterContentBo>>() {
                    String title = titles.poll();

                    @Override
                    public void onSubscribe(Subscription s) {

                        s.request(Integer.MAX_VALUE);
                        mSubscription = s;
                    }

                    @Override
                    public void onNext(List<ChapterContentBo> chapterContentBoList) {

                        //其实是出现过，没有及时取消mSubscription的原因，在RxPresenter中添加这个处理即可
                        mView.finishChapter(chapterContentBoList, flag, null);
                        String content = GsonUtils.obj2String(chapterContentBoList);
                        addDisposable(MediaStorageManager.getInstance().saveChapterInfoInRx(
                                mediaId, title, content
                        ));

//                        mView.finishChapter(content);
                        //将获取到的数据进行存储
                        title = titles.poll();
                    }

                    @Override
                    public void onError(Throwable t) {
                        //只有第一个加载失败才会调用errorChapter
                        if (mediaChapterBeanList.get(0).getName().equals(title)) {
                            mView.errorChapter();
                        }
                        //清除正在执行（已经执行）的章节id
                        for (MediaChapterBean bean : mediaChapterBeanList) {
                            mLoadedChapterIdList.remove(bean.getId());
                        }
                        //清除正在执行加载章节的标记，方便下次请求正常进来不被拦截
                        LogUtils.e(t);

                    }

                    @Override
                    public void onComplete() {

                    }
                });
    }
}
